package com.gitee.wsl.android.ui.spannable.span

import android.content.Context
import android.content.res.Resources
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.text.TextPaint
import android.text.style.ReplacementSpan
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import com.gitee.wsl.android.ext.displayMetrics
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.Locale


class MoneyTextView : ReplacementSpan() {
    private var paddingBottom: Int=0
    private var paddingTop: Int=0
    private var paddingRight: Int=0
    private var paddingLeft: Int=0
    private var mTextPaint: TextPaint? = null
    private var mDecimalFormat: DecimalFormat? = null
    private var mSymbolSection: Section? = null
    private var mIntegerSection: Section? = null
    private var mDecimalSection: Section? = null
    private var mDecimalSeparator = 0.toChar()
    private var mAmount = 0f
    private var mGravity = 0
    private var mSymbolGravity = 0
    private var mDecimalGravity = 0
    private var mSymbolMargin = 0f
    private var mDecimalMargin = 0f
    private var mIncludeDecimalSeparator = false
    private var mWidth = 0
    private var mHeight = 0
    private var mTextPaintRoomSize = 0f

//    app:symbol="$"
//    app:symbolGravity="start|top"
//    app:symbolTextSize="30sp"
//    app:symbolMargin="6dp"
//    app:amount="1256.56"
//    app:baseTextSize="54sp"
//    app:decimalDigitsTextSize="30sp"
//    app:decimalMargin="6dp"
//    app:includeDecimalSeparator="false"
//    app:baseTextColor="#009688"

    private fun init(context: Context, attrs: AttributeSet?) {
        mTextPaint = TextPaint(Paint.ANTI_ALIAS_FLAG)
        mSymbolSection = Section()
        mIntegerSection = Section()
        mDecimalSection = Section()

        mTextPaintRoomSize = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            mTextPaint!!.density,
            context.displayMetrics//displayMetrics
        )

            //mSymbolSection!!.text = typedArray.getString(R.styleable.MoneyTextView_symbol)
            mAmount =  0f
            mGravity = GRAVITY_CENTER_VERTICAL or GRAVITY_CENTER_HORIZONTAL

            mSymbolGravity = GRAVITY_TOP or GRAVITY_START

            mDecimalGravity = GRAVITY_TOP
            mIncludeDecimalSeparator = true
            mSymbolMargin = 0f
            mDecimalMargin = 0f
            mIntegerSection!!.textSize = 12f
            mSymbolSection!!.textSize = mIntegerSection!!.textSize
            mDecimalSection!!.textSize = mIntegerSection!!.textSize

            mIntegerSection!!.color =  0
            mSymbolSection!!.color =  mIntegerSection!!.color
            mDecimalSection!!.color = mIntegerSection!!.color

            mDecimalSection!!.drawUnderline = false

            /*val fontPath = typedArray.getString(R.styleable.MoneyTextView_fontPath)
            if (fontPath != null) {
                val typeface = Typeface.createFromAsset(context.assets, fontPath)
                mTextPaint!!.typeface = typeface
            }*/
            mDecimalFormat = DecimalFormat( "###,##0.00")
            val decimalFormatSymbol = DecimalFormatSymbols(Locale.getDefault())
            mDecimalSeparator = '\''
            decimalFormatSymbol.decimalSeparator = mDecimalSeparator
            mDecimalFormat!!.decimalFormatSymbols = decimalFormatSymbol
            amount = mAmount

    }

     fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
         /*setPadding(
            getMinPadding(paddingLeft), getMinVerticalPadding(paddingTop),
            getMinPadding(paddingRight), getMinVerticalPadding(paddingBottom)
        )*/
        createTextFromAmount()
        calculateBounds(widthMeasureSpec, heightMeasureSpec)
        calculatePositions()
        //setMeasuredDimension(mWidth, mHeight)
    }

    private fun createTextFromAmount() {
        val formattedAmount = mDecimalFormat!!.format(mAmount.toDouble())
        val separatorIndex = formattedAmount.lastIndexOf(mDecimalSeparator)
        if (separatorIndex > -1) {
            mIntegerSection!!.text = formattedAmount.substring(0, separatorIndex)
            mDecimalSection!!.text =
                formattedAmount.substring(if (mIncludeDecimalSeparator) separatorIndex else separatorIndex + 1)
        } else {
            mIntegerSection!!.text = formattedAmount
            mDecimalSection!!.text = ""
        }
    }

    private fun calculateBounds(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val widthMode = View.MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = View.MeasureSpec.getSize(widthMeasureSpec)
        val heightMode = View.MeasureSpec.getMode(heightMeasureSpec)
        val heightSize = View.MeasureSpec.getSize(heightMeasureSpec)
        mSymbolSection!!.calculateBounds(mTextPaint)
        mIntegerSection!!.calculateBounds(mTextPaint)
        mDecimalSection!!.calculateBounds(mTextPaint)
        mDecimalSection!!.calculateNumbersHeight(mTextPaint)
        mIntegerSection!!.calculateNumbersHeight(mTextPaint)
        when (widthMode) {
            View.MeasureSpec.EXACTLY -> mWidth = widthSize
            View.MeasureSpec.AT_MOST, View.MeasureSpec.UNSPECIFIED -> mWidth =
                (mIntegerSection!!.width + mDecimalSection!!.width + mSymbolSection!!.width
                        + mSymbolMargin + mDecimalMargin + paddingLeft + paddingRight).toInt()

            else -> {}
        }
        when (heightMode) {
            View.MeasureSpec.EXACTLY -> mHeight = heightSize
            View.MeasureSpec.AT_MOST, View.MeasureSpec.UNSPECIFIED -> mHeight = (paddingTop + paddingBottom
                    + mIntegerSection!!.height.coerceAtLeast(mDecimalSection!!.height.coerceAtLeast(mSymbolSection!!.height)
            ))
            else -> {}
        }
    }

    private fun calculatePositions() {
        val symbolGravityXAxis = mSymbolGravity and GRAVITY_START
        val symbolGravityYAxis = mSymbolGravity and GRAVITY_TOP
        val fromY: Int
        val fromX: Int
        val width = (mIntegerSection!!.width + mDecimalSection!!.width + mSymbolSection!!.width
                + mSymbolMargin + mDecimalMargin).toInt()
        fromX = if (mGravity and GRAVITY_START == GRAVITY_START) {
            paddingLeft
        } else if (mGravity and GRAVITY_END == GRAVITY_END) {
            mWidth - width - paddingRight
        } else {
            (mWidth shr 1) - (width shr 1)
        }
        fromY = if (mGravity and GRAVITY_TOP == GRAVITY_TOP) {
            paddingTop + mIntegerSection!!.height
        } else if (mGravity and GRAVITY_BOTTOM == GRAVITY_BOTTOM) {
            mHeight - paddingBottom
        } else {
            (mHeight shr 1) + (mIntegerSection!!.height shr 1)
        }
        calculateY(fromY, symbolGravityYAxis)
        calculateX(fromX, symbolGravityXAxis)
    }

    private fun calculateY(from: Int, symbolGravityYAxis: Int) {
        mIntegerSection!!.y = from
        mSymbolSection!!.y =
            from - if (symbolGravityYAxis == GRAVITY_TOP) mIntegerSection!!.height - mSymbolSection!!.height + mSymbolSection!!.bounds.bottom else 0
        mDecimalSection!!.y =
            from - if (mDecimalGravity == GRAVITY_TOP) mIntegerSection!!.height - mDecimalSection!!.height else 0
    }

    private fun calculateX(from: Int, symbolGravityXAxis: Int) {
        if (symbolGravityXAxis == GRAVITY_START) {
            mSymbolSection!!.x = from
            mIntegerSection!!.x =
                (mSymbolSection!!.x + mSymbolSection!!.width + mSymbolMargin).toInt()
            mDecimalSection!!.x =
                (mIntegerSection!!.x + mIntegerSection!!.width + mDecimalMargin).toInt()
        } else {
            mIntegerSection!!.x = from
            mDecimalSection!!.x =
                (mIntegerSection!!.x + mIntegerSection!!.width + mDecimalMargin).toInt()
            mSymbolSection!!.x =
                (mDecimalSection!!.x + mDecimalSection!!.width + mSymbolMargin).toInt()
        }
    }


    private fun drawSection(canvas: Canvas, section: Section?) {
        mTextPaint!!.textSize = section!!.textSize
        mTextPaint!!.color = section.color
        mTextPaint!!.isUnderlineText = section.drawUnderline
        canvas.drawText(
            section.text!!, section.x - mTextPaintRoomSize * 2, section.y - mTextPaintRoomSize / 2,
            mTextPaint!!
        )
    }

    var amount: Float
        get() = mAmount
        set(amount) {
            mAmount = amount
        }

    private fun getMinPadding(padding: Int): Int {
        return if (padding == 0) {
            (MIN_PADDING * Resources.getSystem().displayMetrics.density).toInt()
        } else padding
    }

    private fun getMinVerticalPadding(padding: Int): Int {
        val maxTextSize = Math.max(mIntegerSection!!.textSize, mDecimalSection!!.textSize)
        mTextPaint!!.textSize = maxTextSize
        val maximumDistanceLowestGlyph = mTextPaint!!.fontMetrics.bottom
        return if (padding < maximumDistanceLowestGlyph) {
            maximumDistanceLowestGlyph.toInt()
        } else padding
    }

    private class Section {
        var x = 0
        var y = 0
        var bounds: Rect = Rect()
        var text: String? = null
        var textSize = 0f
        var color = 0
        var width = 0
        var height = 0
        var drawUnderline = false

        fun calculateBounds(paint: TextPaint?) {
            paint!!.textSize = textSize
            paint.getTextBounds(text, 0, text!!.length, bounds)
            width = bounds.width()
            height = bounds.height()
        }

        fun calculateNumbersHeight(paint: TextPaint?) {
            val numbers = text!!.replace("\\D".toRegex(), "")
            paint!!.textSize = textSize
            paint.getTextBounds(numbers, 0, numbers.length, bounds)
            height = bounds.height()
        }
    }

    companion object {
        private const val GRAVITY_START = 1
        private const val GRAVITY_END = 2
        private const val GRAVITY_TOP = 4
        private const val GRAVITY_BOTTOM = 8
        private const val GRAVITY_CENTER_VERTICAL = 16
        private const val GRAVITY_CENTER_HORIZONTAL = 32
        private const val MIN_PADDING = 2f
    }

    override fun getSize(
        paint: Paint,
        text: CharSequence?,
        start: Int,
        end: Int,
        fm: Paint.FontMetricsInt?
    ): Int {
        text?.let { sequence ->
            mDecimalFormat?.parse(sequence.toString())?.let {
                amount=it.toFloat()

                calculatePositions()
            }
        }
        return 3
    }

    override fun draw(
        canvas: Canvas,
        text: CharSequence?,
        start: Int,
        end: Int,
        x: Float,
        top: Int,
        y: Int,
        bottom: Int,
        paint: Paint
    ) {

        drawSection(canvas, mIntegerSection)
        drawSection(canvas, mDecimalSection)
        drawSection(canvas, mSymbolSection)
    }
}